home *** CD-ROM | disk | FTP | other *** search
/ FishMarket 1.0 / FishMarket v1.0.iso / fishies / 426-450 / disk_429 / dr / source / fastexnext.doc < prev    next >
Text File  |  1992-05-06  |  17KB  |  279 lines

  1.  
  2.                          FASTEXAMINE AND FASTEXNEXT
  3.  
  4. As we all know, the AmigaDOG ExNext() function is inexcusably inefficient,
  5. as implemented by the old file system.  This is one way to approach
  6. remedying the symptoms of that lameness.  (Too bad I didn't finish this three
  7. years ago, huh?  Well, I couldn't afford an Amiga then.)
  8.  
  9. The idea here was to make two functions FastExamine() and FastExNext()
  10. which would be completely compatible fast replacements for Examine and
  11. ExNext in C programs.  Unfortunately, the goal of full compatibility has
  12. proven impossible (at least for me), and all that the partial compatibility
  13. means is that it's not too much work to convert an ExNext scanning routine
  14. to a FastExNext routine, and that it's no trouble to internally convert a
  15. FastExNext call to a regular ExNext when necessary.
  16.  
  17. The known differences from the Dos Examine and ExNext functions are:
  18.  
  19.      -- VERY IMPORTANT:  You have to use an extended version of the
  20.         FileInfoBlock struct, with two extra longwords added onto the end.
  21.         Something like this will do:
  22.             struct Fib {
  23.                 struct FileInfoBlock f;         /* no "*" !! */
  24.                 long p, s;
  25.             };
  26.         The last extra field (called s above) must be initialized to either
  27.         zero or negative one.  Use zero if you are not going to do a
  28.         recursive scan of subdirectories (details below).  If you fail to
  29.         initialize this field, prepare to meditate.  Use this struct as you
  30.         would normally use struct FileInfoBlock, like FastExamine(lock, fib).
  31.  
  32.      -- VERY IMPORTANT:  There's a cleanup function you should use if you
  33.         stop scanning before you reach the end of the directory.  Like this:
  34.         FastExCleanup(fib); (where fib is the extended FileInfoBlock you've
  35.         been passing to FastExNext).  Otherwise memory etc. won't be
  36.         deallocated, and in the case of a floppy disk, THE MOTOR WON'T GET
  37. :-(     TURNED OFF until the next file operation.
  38.  
  39.      -- If you want to do a recursive scan of subdirectories, there is
  40.     special optimization you can use, by setting the last longword of the
  41.     extended FileInfoBlock (the s field of struct Fib above) to negative
  42.     one before calling FastExamine.  This will be referred to as using
  43.     "the deep version" in this document.  This optimization works not
  44.     just for recursive descent, but for any succession of nonrepeating
  45.     multiple scans.  It causes FastExNext to remember extra information,
  46.     so as to reduce the amount of disk reading it has to do.
  47.  
  48.      -- The set of possible error returns might be different.  Details below.
  49.  
  50.      -- You can't (yet) start inner FastExNext scans using a fib from an
  51.         outer FastExNext instead of FastExamine'ing the new inner directory
  52.         lock.  You MUST copy the struct Fib and then FastExamine with the
  53.     copy, before using FastExNext on the inner directory.  Or you must at
  54.         least copy the s field and then FastExamine.
  55.  
  56.      -- The files are returned in a different order.
  57.  
  58.      -- These are C functions.  Calling them in assembly has no resemblance
  59.         to calling actual shared library Dos functions.  Furthermore, I have
  60.     no knowledge of whether they will compile correctly without Aztec C,
  61.     though I have no specific reason to think they won't.
  62.  
  63.      -- And, of course, it makes your program bigger (about 5k) and
  64.         greedier.  But not as greedy as you might think.                  ß^)
  65.  
  66.      -- Since we end-run the dos handler and use the device driver task,
  67.         any data buffered in there won't help;  AddBuffers goes to waste.
  68.         But AddBuffers does work for the Fast File System if you're not using
  69.         the deep version, because end running offers no advantage then.
  70.  
  71.      -- Examine often does not need to do any physical IO, but FastExamine
  72.         usually reads one track, and may initiate the reading of another, if
  73.         I ever get around to making the disk IO asynchronous, which I perhaps
  74.         won't because the performance improvement is gonna be petite.
  75.  
  76.      -- FastExNext might return slightly out-of-date information if files are
  77.         being renamed or deleted or whatever during the scan.
  78.  
  79. The cleanup function FastExCleanup() takes as its one parm the pointer to the
  80. extended FileInfoBlock (struct Fib or whatever you want to call it) that
  81. you've been using for the FastExNext scan and returns nothing.  It checks to
  82. see whether it's involved in a current scan that is end-running regular
  83. ExNext, and if so it turns off the disk motor (if it's a floppy), closes the
  84. device, and frees all the memory it was using.  This is done automatically
  85. when you get to the last entry in the directory, and is unnecessary if the
  86. original FastExamine hit a file instead of a directory, if you're not using
  87. the deep version.  If you attempt FastExNext on a FastExCleanup'ed fib, it
  88. will yield ERROR_NO_MORE_ENTRIES, even if the scan wasn't finished.  If you
  89. use the deep version, call FastExCleanup ONLY ONCE when the complete scanning
  90. operation is finished.  Do NOT call it when an inner scan is finished but you
  91. still want to finish an outer scan.  Furthermore, FastExCleanup is NEVER
  92. AUTOMATIC with the deep version, you MUST call it when done scanning.  Even
  93. if the first FastExamine does not return a directory.
  94.  
  95. The easiest way to handle FastExCleanup is not to test for different error
  96. returns, but simply to call it always whenever you know that the directory
  97. scan you are doing is over.  This is the most important change you will have
  98. to make to change an ExNext program into a FastExNext program, besides using
  99. the extended FileInfoBlock in place of the normal one.  It's okay to use
  100. FastExCleanup twice on one fib.
  101.  
  102. One other thing to change, at least in the current version, is this:  with
  103. regular ExNext, you can do a recursive scan of a subdirectory simply by
  104. taking the fib from the ExNext that found this inner directory and passing it
  105. to another ExNext with a lock on that subdirectory.  You can finish the upper
  106. scan with a saved copy of the fib, or abandon it.  With FastExNext, you
  107. currently must start each inner scan with another FastExamine with a separate
  108. fib.  I might fix this someday.  Also:
  109.  
  110. IMPORTANT!  When using the deep version you must start each inner scan using
  111. a fib THAT IS A COPY OF ONE THAT HAS BEEN USED IN A PREVIOUS SCAN; you cannot
  112. start with a blank fib.  Or at least you must copy the value in the last
  113. longword (the s field).  None of the optimization will work if this
  114. information doesn't get transferred, and it might also fail to free some
  115. memory.  And I aint gonna promise that worse things won't happen.
  116.  
  117. These functions call regular Examine and ExNext in cases which they can't
  118. optimize.  This happens when it's not a true AmigaDos disk, but instead
  119. something like RAM:, or when the block size is not 512 bytes (I guess I
  120. should fix that someday) (but I heard that the file system itself can't even
  121. handle such yet), also in the case of a null lock (note that if you DupLock a
  122. null you get null, but if you have a null CD and go Lock("", ACCESS_READ),
  123. you get a real non-null lock), or when there's not enough contiguous memory
  124. for a track buffer (some disks need chip ram, others don't), or if OpenDevice
  125. fails (unlikely).  One more condition:  if the disk has a MaxTransfer mount
  126. parameter that is set to a size smaller than one track, and the size of the
  127. track is not evenly divisible by the MaxTransfer size (rounded down to the
  128. nearest whole sector), then it will call regular ExNext.  So far the only
  129. instances I've seen are 8K MaxTransfer on 16K tracks, with Quantum Q40
  130. drives.  (These would cause gurus in an earlier version before I paid
  131. attention to MaxTransfer.)  The performance of this thing is just about equal
  132. to the Fast File System, or superior to it if you are using the deep version
  133. for multiple directories.
  134.  
  135. This version can set the following IoErr codes in addition to 232 (no more
  136. entries):  103 if you run out of memory, 211 if you pass it an invalid lock
  137. (not guaranteed to catch all bad locks), 218 (not mounted) if you pop the
  138. disk out of the drive and cancel the "please replace" requester, and 225 (not
  139. a dos disk) if there's a hardware IO error or other general trouble in
  140. reading the disk.  (Why is there no DOS error number for hardware errors??)
  141. Also, if perchance you pass it a null FileInfoBlock pointer, it indicates an
  142. error condition by crashing the system.  I don't know what the full set of
  143. possible error returns from vanilla Examine / ExNext is.
  144.  
  145. When to stop scanning:  Official Amiga programs don't seem to agree whether
  146. you should stop scanning when ExNext returns an error other than 232 (no
  147. more entries).  Dir abandons the scan, List sometimes keeps trying, like
  148. when you pop the disk out, even cancelling the "Please replace" requester
  149. doesn't stop it, it keeps putting out the same output line until the disk
  150. goes back in or you use control-C.  With FastExNext, my goal is that you can
  151. continue past error if the error is 218 (not mounted) or 225 (not a dos disk
  152. = device level error).  You won't get a complete directory list under such
  153. conditions, and I'm not too sure if that works, so I recommend abandoning
  154. the scan and calling FastExCleanup.  Particularly you should abandon the scan
  155. if the user has clicked Cancel on a "Please replace..." requester, which will
  156. have happened if you get error 218 and your pr_WindowPtr is not -1.  Old
  157. ExNext sets IoErr 218 if the disk is out of the drive, with a "Please replace
  158. ... in any drive" requester, as opposed to the "... in unit  N" requester that
  159. FastExNext uses, but if you pop the disk out during a hardware read and
  160. cancel the "You MUST replace ... in unit  N !!!" requester, it sets IoErr to
  161. (of all things) 232 "no more entries"!  How bogus!  And also, how bogus to
  162. say "You MUST replace ... !!!" for a read-only operation that it actually
  163. recovers from with no problems, as far as I can tell.
  164.  
  165. A note about System Requests that pop up when there's an error:  I had to
  166. mimic the official system requesters by hand, sort of, and I have discovered
  167. that the intuition AutoRequest function is the one part of this that is
  168. capable of guruing when memory is low.  It's supposed to display an alert
  169. under such conditions, but only does so if the memory is just slightly too
  170. low (it needs 6k of contiguous chip ram to DisplayAlert).  (THANKS TO JOHN
  171. GERLACH JR for AllocMaster, which helped me to make most of this pretty
  172. bulletproof under low memory conditions.)  There are two requesters which
  173. this can fire up:  "Please replace volume Xxxxxxxx in unit  N" and "Volume
  174. Xxxxxxxxxxx has a read/write error".  This latter does not necessarily mean a
  175. physically defective disk or drive.  Elsewhere in Dos this can come up if
  176. there is simply a bogus block pointer somewhere.  This is used as a catchall
  177. for all device level errors other than popping out the disk.  In BCPL I think
  178. there is a ROM function for firing up an appropriate disk trouble requester
  179. which automatically knows what to say.  Too bad the rest of us don't get to
  180. see such a thing.
  181.  
  182. Late addendum to above:  Now FastExNext does not include the System Request
  183. feature unless you compile it with the word QUEST #defined.  Otherwise errors
  184. simply fall through to the calling program with no requester interruption.
  185.  
  186. (Actually, it is remotely possible to get a "You MUST replace !!!" requester
  187. by popping out a disk during a FastExNext scan.  I have only seen this
  188. rarely.  When you put it back in and click retry (which you must do
  189. manually), FastExNext's own "Please replace" then comes up.  I do not
  190. understand the cause of this, or how to detect it.)
  191.  
  192.  
  193. MY NOTES ON REGULAR EXAMINE AND EXNEXT:
  194. There is no extra data hidden in the fib.  Apparently they simply go by the
  195. key field and the hash value of the name, which sometimes causes rereading of
  196. the block(s) they just read, if they get interleaved with other disk
  197. activity.  The EntryType and DirEntryType fields apparently always hold the
  198. same value:  2 for a directory, including a root directory, or -3 for a file.
  199. ExNext reads sequentially through the hash table, chasing each list to the
  200. end and then scanning for the next nonzero hash entry.  It puts zero in the
  201. length and blocks fields for directories.  Examine works correctly with a
  202. null lock.  Bryce Nesbitt says that ExNext pursues chains of extension blocks
  203. just to get an exact count of blocks used.  Forget it, I'm just gonna
  204. calculate the block consumption from the length in bytes.  Which should work
  205. except for those times when people create bogus zero-length files full of bad
  206. blocks and suchlike.
  207.  
  208. ExNext works like this under the Fast File System:  Examine scarfs the table
  209. of block numbers in the directory header, and ExNext simply sorts them and
  210. reads through them from lowest to highest.  Discovering new blocks to read
  211. on hash lists doesn't disrupt the order because the FFS always maintains the
  212. hash lists in sorted order, with lower numbered blocks pointing to higher
  213. numbered ones, so ExNext can insert them into the part of the sorted list
  214. that hasn't been handled yet.
  215.  
  216. I've noticed that if you call Examine and then ExNext when the lock is on a
  217. file, not a directory, it puts up a "read/write error" requester.  I opine
  218. that this is way bogus.  FastExNext will simply return ERROR_NO_MORE_ENTRIES,
  219. unless it is just passing the call through to regular ExNext.
  220.  
  221.  
  222. HOW FASTEXNEXT WORKS:
  223. FastExamine scarfs the entire track that the directory or file being examined
  224. is on, and saves the hash table plus any blocks on that same track that point
  225. to that directory as parent.  Any blocks which do so and are also mentioned
  226. in the hash table get pushed onto a "ready" list.  Any which are not men-
  227. tioned in the hash table go into the "maybe" group, which is stored as a
  228. binary tree.  Each file consumes about 80 bytes of memory, or twice that if
  229. it has a filenote, plus some more to hold its hash table if it is a directory
  230. and you're using the deep version.  Each file put on the ready list gets its
  231. number removed from the hash table, and if it has a hash chain pointer, that
  232. number gets inserted into an empty space in the table, and the maybe tree is
  233. checked to see if this block is present there.  If so, that one is moved from
  234. the maybe group to the ready group, and its hash pointer is similarly
  235. checked.  The total count of block numbers in the table never increases.
  236. Whenever you ExNext, it simply returns a file from the ready list.  If the
  237. ready list is empty, it reads the track which contains the block number in
  238. the hash table which is closest to the last track read (assumed to be zero at
  239. the beginning).  It then checks this track for readies and maybes just like
  240. the first track.  This process continues until both the ready list and the
  241. hash table are empty, at which time it automatically calls FastExCleanup.
  242.  
  243. It's not quite as efficient as the Fast File System when operating on a Slow
  244. File System volume, because a pointer found in a hash chain might cause it to
  245. skip back to a track it already passed over, and because it can't make use of
  246. blocks buffered inside the file system (that is, AddBuffers doesn't help),
  247. but it will never read the same track twice.  Unless it runs out of memory,
  248. in which case it will "forget" some of the maybes, which might cause it to
  249. reread a track if a maybe it forgot turned out to be needed after all.  On
  250. the fast file system when not using the deep version, usually no maybies
  251. would be saved at all because of the sorted hash chains.  For this reason
  252. there is no performance advantage, so we use regular ExNext which can take
  253. advantage of AddBuffers.
  254.  
  255. The deep version works by simply remembering ALL files and directories it
  256. finds on any track it reads in the maybe tree.  This can consume many K of
  257. memory if it reads lots of tracks on a hard disk.  But it saves a lot of disk
  258. IO, because if some directory needs to check a track that some other
  259. directory has already referenced, the information is waiting for it.
  260. Directories that are found get their hash tables saved in an area separate
  261. from the maybe tree.  (In fact, a redundant copy of the information in the
  262. maybe tree is kept there, just to simplify coding.)  No track is read twice
  263. between the first FastExamine and the final FastExCleanup, given enough
  264. memory.  An inner FastExamine will take its information from the maybe tree
  265. instead of reading the disk, if the relevant track has already been read.
  266.  
  267. FastExamine and FastExNext are written in Aztec C by
  268.  
  269.                 Paul Kienitz                email: none. BBSes: try
  270.                 6430 San Pablo ave.           Winners Circle 415-845-4812
  271.                 Oakland, CA  94608            Triple-A 415-222-9416
  272.                 USA                           Just Computing 415-961-7250
  273.                                               FAUG 415-515-2479
  274.  
  275. and are in the public domain.  Feedback is appreciated, ESPECIALLY if you
  276. find some device it doesn't work with (I know of none), or any bug, or know a
  277. way to make it smaller and/or better.  I suppose I could make a shared
  278. library out of it...
  279.